///////////////////////////////////////////////
///      Product Name: WordQuicker          ///
/// Copyright (c)2007, Marstone Studio      ///
///           Author: marstone              ///
///        Web Site: marstone.net           ///
///      Mail/MSN: marstone@163.com         ///
///         Created: 2007.09.26             ///
///      Last Modified: 2007.09.27          ///
///////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Text;
using Word = Microsoft.Office.Interop.Word;

namespace Studio.Windows.WordQuicker
{
    /// <summary>
    /// Document interface
    /// </summary>
    public class WQDocumentClass : WQDocument
    {
        /// <summary>
        /// The real Embedded Word Document Object
        /// </summary>
        Word.Document WordDocument = null;

        /// <summary>
        /// Construct the WQDocument Object, The Encapsulation of Word.Document Class
        /// </summary>
        /// <param name="WordDoc"></param>
        public WQDocumentClass(Word.Document WordDoc) { WordDocument = WordDoc; }

        /// <summary>
        /// Fill Blank after specified Bookmark
        /// </summary>
        public void FillByBookmark(string Bookmark, string TextToFill)
        {
            // Location the Bookmark first
            if (false == WordDocument.Bookmarks.Exists(Bookmark))
                throw new Exception("Bookmark not found in FillByBookmark.");

            Object bookmark = Bookmark;
            WordDocument.Bookmarks.get_Item(ref bookmark).Range.Text = TextToFill;
        }

        /// <summary>
        /// SaveAs, overwrite without prompt
        /// </summary>
        public bool SaveDocumentAs(string NewFileName)
        {     
            // Save the document. In a real application,
            // you'd want to test to see if the file
            // already exists. This will overwrite any previously 
            // existing documents.
            Object fileName = NewFileName;
            Object fileFormat = Type.Missing;
            Object lockComments = Type.Missing;
            Object password = Type.Missing;
            Object addToRecentFiles = Type.Missing;
            Object writePassword = Type.Missing;
            Object readOnlyRecommended = Type.Missing;
            Object embedTrueTypeFonts = Type.Missing;
            Object saveNativePictureFormat = Type.Missing;
            Object saveFormsData = Type.Missing;
            Object saveAsAOCELetter = Type.Missing;
            Object encoding = Type.Missing;
            Object insertLineBreaks = Type.Missing;
            Object allowSubstitutions = Type.Missing;
            Object lineEnding = Type.Missing;
            Object addBiDiMarks = Type.Missing;

            try
            {
                WordDocument.SaveAs(ref fileName, ref fileFormat, ref lockComments,
                  ref password, ref addToRecentFiles, ref writePassword,
                  ref readOnlyRecommended, ref embedTrueTypeFonts, ref saveNativePictureFormat,
                  ref saveFormsData, ref saveAsAOCELetter, ref encoding,
                  ref insertLineBreaks, ref allowSubstitutions, ref lineEnding,
                  ref addBiDiMarks);

                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return false;
            }
        }

        /// <summary>
        /// Find table 
        /// </summary>
        public WQTable LocateTable(int Index)
        {
            if (Index < 1 || Index > TableCount)
                throw new Exception("Table index is out of range in FindTable");

            Word.Table WordTable = WordDocument.Tables[Index];

            return new WQTableClass(WordTable);
        }


        /// <summary>
        /// Save if not readonly
        /// </summary>
        public bool SaveDocument()
        {
            if (false == WordDocument.ReadOnly)
            {
                WordDocument.Save();
                return true;
            }
            else
                return false;
        }


        /// <summary>
        /// Inner table count
        /// </summary>
        public int TableCount
        {
            get 
            {
                return WordDocument.Tables.Count;
            }
        }

        /// <summary>
        /// Replace from the Beginning. The Find direction is Forward.
        /// </summary>
        public bool ReplaceOne(string Pattern, string Substitute)
        {
            // range all
            Object Start = 0;
            Object End = WordDocument.Characters.Count;
            Word.Range RangeTotal = WordDocument.Range(ref Start, ref End);
            // execute Replace
            Word.Find Find = RangeTotal.Find;
            Find.ClearFormatting();
            Find.Text = Pattern;
            Find.Forward = true;
            Find.Replacement.ClearFormatting();

            int MaxLengthSupported = 64;

            while (Substitute.Length > MaxLengthSupported)
            {
                string StringWithPattern = Substitute.Substring(0, MaxLengthSupported) + Pattern;
                Substitute = Substitute.Substring(MaxLengthSupported);
                Find.Replacement.Text = StringWithPattern;
                ExecuteReplace(Find, Word.WdReplace.wdReplaceOne);
            }

            Find.Replacement.Text = Substitute;
            return ExecuteReplace(Find, Word.WdReplace.wdReplaceOne);
        }

        public bool ReplaceAll(string Pattern, string Substitute)
        {
            // range all
            Object Start = 0;
            Object End = WordDocument.Characters.Count;
            Word.Range RangeTotal = WordDocument.Range(ref Start, ref End);
            // execute Replace
            Word.Find Find = RangeTotal.Find;
            Find.ClearFormatting();
            Find.Text = Pattern;
            Find.Forward = true;
            Find.Replacement.ClearFormatting();
            Find.Replacement.Text = Substitute;
            return ExecuteReplace(Find, Word.WdReplace.wdReplaceAll);
        }


        #region Find Method Wrappers

        private Boolean ExecuteReplace(Word.Find find, Object replaceOption)
        {
            // Simple wrapper around Find.Execute:
            Object findText = Type.Missing;
            Object matchCase = Type.Missing;
            Object matchWholeWord = Type.Missing;
            Object matchWildcards = Type.Missing;
            Object matchSoundsLike = Type.Missing;
            Object matchAllWordForms = Type.Missing;
            Object forward = Type.Missing;
            Object wrap = Type.Missing;
            Object format = Type.Missing;
            Object replaceWith = Type.Missing;
            Object replace = replaceOption;
            Object matchKashida = Type.Missing;
            Object matchDiacritics = Type.Missing;
            Object matchAlefHamza = Type.Missing;
            Object matchControl = Type.Missing;

            return find.Execute(ref findText, ref matchCase, ref matchWholeWord,
              ref matchWildcards, ref matchSoundsLike, ref matchAllWordForms,
              ref forward, ref wrap, ref format, ref replaceWith, ref replace,
              ref matchKashida, ref matchDiacritics, ref matchAlefHamza,
              ref matchControl);
        }

        private Boolean ExecuteFind(Word.Find find)
        {
            return ExecuteFind(find, Type.Missing, Type.Missing);
        }

        private Boolean ExecuteFind(
          Word.Find find, Object wrapFind, Object forwardFind)
        {
            // Simple wrapper around Find.Execute:
            Object findText = Type.Missing;
            Object matchCase = Type.Missing;
            Object matchWholeWord = Type.Missing;
            Object matchWildcards = Type.Missing;
            Object matchSoundsLike = Type.Missing;
            Object matchAllWordForms = Type.Missing;
            Object forward = forwardFind;
            Object wrap = wrapFind;
            Object format = Type.Missing;
            Object replaceWith = Type.Missing;
            Object replace = Type.Missing;
            Object matchKashida = Type.Missing;
            Object matchDiacritics = Type.Missing;
            Object matchAlefHamza = Type.Missing;
            Object matchControl = Type.Missing;

            return find.Execute(ref findText, ref matchCase, ref matchWholeWord,
              ref matchWildcards, ref matchSoundsLike, ref matchAllWordForms,
              ref forward, ref wrap, ref format, ref replaceWith, ref replace,
              ref matchKashida, ref matchDiacritics, ref matchAlefHamza,
              ref matchControl);
        }
        #endregion


        public void InsertAfterBookmark(string Bookmark, string TextToInsert)
        {
            // Location the Bookmark first
            if (false == WordDocument.Bookmarks.Exists(Bookmark))
                throw new Exception("Bookmark not found in InsertAfterBookmark.");

            Object bookmark = Bookmark;
            WordDocument.Bookmarks.get_Item(ref bookmark).Range.InsertAfter(TextToInsert);
        }

        public void CopyAfterBookmark(string BookmarkDest, string BookmarkSource)
        {
            // Location the Bookmark first
            if (false == WordDocument.Bookmarks.Exists(BookmarkDest) ||
                false == WordDocument.Bookmarks.Exists(BookmarkSource))
                throw new Exception("Bookmark not found in CopyAfterBookmark.");
            // Get Bookmark
            Object dst = BookmarkDest;
            Object src = BookmarkSource;
            Word.Bookmark bmdst = WordDocument.Bookmarks.get_Item(ref dst);
            Word.Bookmark bmsrc = WordDocument.Bookmarks.get_Item(ref src);
            // Copy
            bmsrc.Range.Copy();

            bmdst.Range.Paste();
        }


        public void CloseDocument(bool IsSave)
        {
            Object saveChanges = IsSave ? Word.WdSaveOptions.wdSaveChanges : Word.WdSaveOptions.wdDoNotSaveChanges;
            Object originalFormat = Type.Missing;
            Object routeDocument = Type.Missing;
            WordDocument.Close(ref saveChanges, ref originalFormat, ref routeDocument);
        }
    }
}
